#include "../ModuleB/copy.h"
#include "function.h"

// 计算目录总字节数
void calculate_total_bytes(const char *dir) {
    DIR *dir_handle;
    struct dirent *entry;
    struct stat stat_info;

    if ((dir_handle = opendir(dir)) == NULL) {
        perror("opendir");
        return;
    }

    while ((entry = readdir(dir_handle)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char entry_path[PATH_MAX];
        snprintf(entry_path, PATH_MAX, "%s/%s", dir, entry->d_name);

        if (lstat(entry_path, &stat_info) == -1) {
            perror("lstat");
            continue;
        }

        if (S_ISDIR(stat_info.st_mode)) {
            calculate_total_bytes(entry_path);
        } else if (S_ISREG(stat_info.st_mode)) {
            total_bytes += stat_info.st_size;
        }
    }

    closedir(dir_handle);
}

// 显示总进度条
void display_total_progress() {
    double percentage = (double)atomic_load(completed_bytes) / total_bytes;
    int bar_length = 50;
    int num_chars = (int)(percentage * bar_length);

    printf("[");
    for (int i = 0; i < num_chars; i++) {
        printf("=");
    }
    for (int i = num_chars; i < bar_length; i++) {
        printf(" ");
    }
    printf("] %.2f%%\r", percentage * 100);
    fflush(stdout);
}

// 显示总进度
void progress_process() {
    while (1) {
        display_total_progress();

        if (atomic_load(completed_bytes) >= total_bytes) {
            printf("\n");
            break;
        }

        sleep(1);
    }
}

// 从用户输入中获取备份任务（备份） 
int getBackupTasks_1(struct BackupTask tasks[], int max_tasks) {
    int task_count = 0;
    char source[PATH_MAX];
    char destination[PATH_MAX];

    printf("输入源路径和目标路径（输入end结束输入）:\n");

    while (task_count < max_tasks) {
        printf("源路径: ");
        if (scanf("%s", source) != 1) {
            fprintf(stderr, "输入错误\n");
            exit(1);
        }

        if (strcmp(source, "end") == 0) {
            break;
        }

        printf("目标路径: ");
        if (scanf("%s", destination) != 1) {
            fprintf(stderr, "输入错误\n");
            exit(1);
        }

        tasks[task_count].source = strdup(source);
        tasks[task_count].destination = strdup(destination);
        tasks[task_count].way = strdup("1");

        if (tasks[task_count].source == NULL || tasks[task_count].destination == NULL || tasks[task_count].way == NULL) {
            perror("内存分配错误");
            exit(1);
        }

        task_count++;
    }
    return task_count;
}

// 从用户输入中获取备份任务（同步） 
int getBackupTasks_2(struct BackupTask tasks[], int max_tasks) {
    int task_count = 0;
    char source[PATH_MAX];
    char destination[PATH_MAX];
    char way[PATH_MAX];

    printf("输入源路径,目标路径和同步方式（输入end结束输入）:\n");

    while (task_count < max_tasks) {
        printf("源路径: ");
        if (scanf("%s", source) != 1) {
            fprintf(stderr, "输入错误\n");
            exit(1);
        }

        if (strcmp(source, "end") == 0) {
            break;
        }

        printf("目标路径: ");
        if (scanf("%s", destination) != 1) {
            fprintf(stderr, "输入错误\n");
            exit(1);
        }
        
        printf("同步方式\n");
        printf("1：A->B\n");
        printf("2：B->A\n");
        printf("3: 双向同步\n");
        printf("请输入："); 
        if (scanf("%s", way) != 1) {
            fprintf(stderr, "输入错误\n");
            exit(1);
        }

        tasks[task_count].source = strdup(source);
        tasks[task_count].destination = strdup(destination);
        tasks[task_count].way = strdup(way);

        if (tasks[task_count].source == NULL || tasks[task_count].destination == NULL || tasks[task_count].way == NULL) {
            perror("内存分配错误");
            exit(1);
        }

        task_count++;
    }
    return task_count;
}

// 获取文件的修改时间
time_t get_file_mtime(const char *path) {
    struct stat stat_info;
    if (stat(path, &stat_info) == -1) {
        perror("stat");
        return -1;
    }
    return stat_info.st_mtime;
}

// 递归删除文件或目录
void deleteFileOrDir(const char *path) {
    struct stat file_stat;
    if (stat(path, &file_stat) == -1) {
        perror("stat");
        return;
    }

    if (S_ISDIR(file_stat.st_mode)) {
        DIR *dir = opendir(path);
        if (dir == NULL) {
            perror("opendir");
            return;
        }

        struct dirent *entry;
        while ((entry = readdir(dir)) != NULL) {
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                continue;
            }

            char sub_path[PATH_MAX];
            snprintf(sub_path, sizeof(sub_path), "%s/%s", path, entry->d_name);
            deleteFileOrDir(sub_path);
        }

        closedir(dir);

        if (rmdir(path) == -1) {
            perror("rmdir");
        }
    } else {
        if (remove(path) == -1) {
            perror("remove");
        }
    }
}

// 单向同步
void sync_A_to_B(const char *source, const char *destination) {
    DIR *dir;
    struct dirent *entry;
    
    if ((dir = opendir(destination)) == NULL) {
        perror("opendir");
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char source_path[PATH_MAX];
        char dest_path[PATH_MAX];

        snprintf(source_path, PATH_MAX, "%s/%s", source, entry->d_name);
        snprintf(dest_path, PATH_MAX, "%s/%s", destination, entry->d_name);

        if (access(source_path, F_OK) == -1) {
            deleteFileOrDir(dest_path);
        }
    }

    closedir(dir);

    if ((dir = opendir(source)) == NULL) {
        perror("opendir");
        return;
    }

    copy_directory(source, destination);
}

// 计算双向同步中同步的总字节数
void compare_directories(const char *source, const char *destination) {
    DIR *dir;
    struct dirent *entry;
    struct stat stat_info,stat_source;

    if ((dir = opendir(source)) == NULL) {
        perror("opendir");
        return;
    }

    if (access(destination, F_OK) == -1) {
        if (mkdir(destination, 0755) == -1) {
            perror("mkdir");
            return;
        }
    }

    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char source_path[PATH_MAX];
        char dest_path[PATH_MAX];

        snprintf(source_path, PATH_MAX, "%s/%s", source, entry->d_name);
        snprintf(dest_path, PATH_MAX, "%s/%s", destination, entry->d_name);

        if (lstat(source_path, &stat_info) == -1) {
            perror("lstat");
            continue;
        }
        stat(source_path, &stat_source);

        if (S_ISDIR(stat_info.st_mode)) {
            compare_directories(source_path, dest_path);
        } else if (S_ISREG(stat_info.st_mode)) {
        	if(access(dest_path, F_OK) == -1){
		        total_bytes += stat_source.st_size;
		    }else{
		    	time_t source_mtime = get_file_mtime(source_path);
                time_t dest_mtime = get_file_mtime(dest_path);
                if (source_mtime > dest_mtime) {
                    total_bytes += stat_source.st_size;
                }
			}
        }
    }

    closedir(dir);
}

// 双向同步
void bidirectional_sync(const char *source, const char *destination) {
    DIR *dir;
    struct dirent *entry;
    struct stat stat_info;

    if ((dir = opendir(source)) == NULL) {
        perror("opendir");
        return;
    }

    if (access(destination, F_OK) == -1) {
        if (mkdir(destination, 0755) == -1) {
            perror("mkdir");
            return;
        }
    }

    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char source_path[PATH_MAX];
        char dest_path[PATH_MAX];

        snprintf(source_path, PATH_MAX, "%s/%s", source, entry->d_name);
        snprintf(dest_path, PATH_MAX, "%s/%s", destination, entry->d_name);

        if (lstat(source_path, &stat_info) == -1) {
            perror("lstat");
            continue;
        }

        if (S_ISDIR(stat_info.st_mode)) {
            bidirectional_sync(source_path, dest_path);
        } else if (S_ISREG(stat_info.st_mode)) {
        	if(access(dest_path, F_OK) == -1){
		        if (stat_info.st_size > 500 * 1024 * 1024) {
		            copy_large_file_multithreaded(source_path, dest_path);
		        } else {
		            copy_file(source_path, dest_path);
		        }
		    }else{
		    	time_t source_mtime = get_file_mtime(source_path);
                time_t dest_mtime = get_file_mtime(dest_path);
                if (source_mtime > dest_mtime) {
                    if (stat_info.st_size > 500 * 1024 * 1024) {
			            copy_large_file_multithreaded(source_path, dest_path);
			        } else {
			            copy_file(source_path, dest_path);
			        }
                } else {
                	if (stat_info.st_size > 500 * 1024 * 1024) {
			            copy_large_file_multithreaded(dest_path, source_path);
			        } else {
			            copy_file(dest_path, source_path);
			        }
				}
			}
        }
    }

    closedir(dir);
    
    DIR *dir_dest;
    if ((dir_dest = opendir(destination)) == NULL) {
        perror("opendir destination");
        return;
    }

    while ((entry = readdir(dir_dest)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char source_path[PATH_MAX];
        char dest_path[PATH_MAX];

        snprintf(source_path, PATH_MAX, "%s/%s", source, entry->d_name);
        snprintf(dest_path, PATH_MAX, "%s/%s", destination, entry->d_name);

        if (lstat(dest_path, &stat_info) == -1) {
            perror("lstat destination");
            continue;
        }

        if (S_ISREG(stat_info.st_mode)) {
            if (access(source_path, F_OK) == -1) {
                if (stat_info.st_size > 500 * 1024 * 1024) {
		            copy_large_file_multithreaded(dest_path, source_path);
		        } else {
		            copy_file(dest_path, source_path);
		        }
            }
        }
    }

    closedir(dir_dest);
}


